package com.loyal.camerax.ui

import android.app.Activity
import android.os.Bundle
import android.util.Log
import android.view.OrientationEventListener
import android.widget.ImageButton
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageCapture
import androidx.camera.core.Preview
import androidx.camera.core.impl.ImageOutputConfig
import androidx.camera.core.resolutionselector.ResolutionSelector
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.concurrent.futures.await
import androidx.lifecycle.lifecycleScope
import androidx.window.layout.WindowMetrics
import androidx.window.layout.WindowMetricsCalculator
import com.loyal.camerax.R
import com.loyal.camerax.config.PhotoConfig
import com.loyal.camerax.impl.PicturePreviewCallback
import com.loyal.camerax.ui.base.BaseCameraActivity
import com.loyal.camerax.utils.ActivityHelper.orientationChanged
import com.loyal.camerax.utils.ActivityHelper.surfaceRotation
import com.loyal.camerax.utils.aspectRatio
import com.loyal.camerax.utils.hasBackCamera
import com.loyal.camerax.utils.hasFrontCamera
import com.loyal.camerax.utils.observeCameraState
import com.loyal.camerax.utils.removeObservers
import com.loyal.camerax.utils.switchCameraId
import com.loyal.camerax.utils.takePhotoByByteArray
import com.loyal.camerax.utils.zoomAndFocus
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

open class CameraActivity : BaseCameraActivity(), PicturePreviewCallback {

    private var lensFacing = CameraSelector.LENS_FACING_BACK
    private var preview: Preview? = null
    private var imageCapture: ImageCapture? = null
    private var imageAnalysis: ImageAnalysis? = null
    private var camera: Camera? = null
    private var cameraProvider: ProcessCameraProvider? = null
    private lateinit var windowMetrics: WindowMetrics
    private lateinit var cameraExecutor: ExecutorService

    /**自动*/
    private var mOrientationListener: OrientationEventListener? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mOrientationListener = orientationChanged()
    }

    override fun initCamerax() {
        cameraExecutor = Executors.newSingleThreadExecutor()
        windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)

        binding.previewView.apply {
            post {
                setCameraUI()
                lifecycleScope.launch {
                    setUpCamera()
                }
            }
        }
    }

    private suspend fun setUpCamera() {
        cameraProvider = ProcessCameraProvider.getInstance(this).await()
        val hasBackCamera = cameraProvider.hasBackCamera()
        val hasFrontCamera = cameraProvider.hasFrontCamera()
        binding.cameraPanel.cameraSwitch.isEnabled = hasBackCamera && hasFrontCamera

        lensFacing = when {
            cameraProvider.hasBackCamera() -> CameraSelector.LENS_FACING_BACK
            cameraProvider.hasFrontCamera() -> CameraSelector.LENS_FACING_FRONT
            else -> throw IllegalStateException("Back and front camera are unavailable")
        }

        bindCameraUseCases()
        stateCallback()
    }

    override fun stateCallback() {
        camera?.cameraInfo?.torchState?.observe(this) {
            Log.e(TAG, "switchFlash: $it")
        }
    }

    private fun bindCameraUseCases() {
        val metrics = windowMetrics.bounds
        val screenAspectRatio = aspectRatio(metrics.width(), metrics.height())
        val rotation = surfaceRotation()
        //binding.previewView.display.rotation
        Log.e(TAG, "rotation: $rotation")
        val cameraProvider =
            cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
        val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()

        val resolutionSelector = ResolutionSelector.Builder()
            .setAspectRatioStrategy(screenAspectRatio)
            .build()
        // 预览
        preview = Preview.Builder()
            .setResolutionSelector(resolutionSelector)
            //旋转角度
            .setTargetRotation(rotation).build()

        // 图片分析
        imageAnalysis = ImageAnalysis.Builder()
            //Resolution 和 AspectRatio->设置其中一个即可，★不能同时设置这两个值。
            .setResolutionSelector(resolutionSelector)
            //旋转角度
            .setTargetRotation(rotation)
            .build()

        // 拍照
        imageCapture = ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            .setResolutionSelector(resolutionSelector)
            .setTargetRotation(rotation)
            .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
            .build()

        cameraProvider.unbindAll()
        camera?.cameraInfo?.removeObservers(this)

        try {
            camera = cameraProvider.bindToLifecycle(
                this, cameraSelector, preview, imageCapture, imageAnalysis
            )
            if (camera?.cameraInfo?.hasFlashUnit() == true)
                imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
            preview?.setSurfaceProvider(binding.previewView.surfaceProvider)
            camera?.cameraInfo.observeCameraState(this)
            //缩放
            camera.zoomAndFocus(binding.previewView, binding.focusView, cameraExecutor)
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
    }

    override fun updateTorchFlash(view: ImageButton, value: String?): Boolean {
        val hasFlash = camera?.cameraInfo?.hasFlashUnit() ?: false
        if (!hasFlash) return false
        when (value) {
            getString(R.string.flash_value_on) -> {
                imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
                camera?.cameraControl?.enableTorch(false)
                view.setImageResource(R.drawable.flash_on)
            }

            getString(R.string.flash_value_auto) -> {
                imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
                camera?.cameraControl?.enableTorch(false)
                view.setImageResource(R.drawable.flash_auto)
            }

            getString(R.string.flash_value_torch) -> {
                imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
                camera?.cameraControl?.enableTorch(true)
                view.setImageResource(R.drawable.flash_torch)
            }

            else -> {
                imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
                camera?.cameraControl?.enableTorch(false)
                view.setImageResource(R.drawable.flash_off)
            }
        }
        return true
    }

    override fun switchCamera() {
        lensFacing = switchCameraId(lensFacing)
        bindCameraUseCases()
    }

    override fun takePhoto() {
        val newPath = savePath().ifEmpty {
            filesDir.path
        }

        val fileName = saveName().ifEmpty {
            SimpleDateFormat("yyyyMMdd-HHmmss", Locale.US)
                .format(System.currentTimeMillis())
        }
        val imageFile = File(newPath, "$fileName.jpg")

        val isFrontPhoto = CameraSelector.LENS_FACING_FRONT == lensFacing
        Log.e(TAG, "isFrontPhoto: $isFrontPhoto")

        val config = PhotoConfig(
            horizontalMirror = isFrontPhoto,
            imageFile = imageFile,
            enableCompress = true,
        )
        imageCapture.takePhotoByByteArray(this, config, cameraExecutor) {
            if (it) setGalleryThumbnail(imageFile.path)
        }
    }

    override fun restart(activity: Activity) {
        camera?.cameraInfo?.removeObservers(this)
        cameraProvider?.unbindAll()
        super.restart(activity)
    }

    fun updateViewRotation(
        rotation: Float,
        @ImageOutputConfig.RotationValue targetRotation: Int
    ) {
        settingsBinding().apply {
            cameraSetting.rotation = rotation
            flashSwitch.rotation = rotation
        }
        cameraBinding().apply {
            cameraSwitch.rotation = rotation
            cameraGallery.rotation = rotation
        }
        imageCapture?.targetRotation = targetRotation
        imageAnalysis?.targetRotation = targetRotation
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
        mOrientationListener?.disable()
    }

    companion object {
        private const val TAG = "CameraxActivity"

    }
}